/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "odbc_recordset.h"
#include "odbc_connect.h"
#include "mgr.h"

namespace xos_odbc
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    static odbc_recordset::ITEM_DATA xos_item_data;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    odbc_recordset::odbc_recordset()
    {
        init_data();
    }

    odbc_recordset::~odbc_recordset()
    {
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int odbc_recordset::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int odbc_recordset::set_connect( i_connect * lpConnect )
    {
        int ret = 0;
        m_pConnect = lpConnect;
        return ret;
    }

    int odbc_recordset::init()
    {
        int ret = 0;
        return ret;
    }

    int odbc_recordset::term()
    {
        int ret = 0;

        field_list.put_back_to_pool();
        close_stmt();
        init_data();

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    int odbc_recordset::get_str_from_buf()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); iter != field_list.end(); ++iter )
        {
            odbc_field::T * pF = *iter;
            if( i_stmt::VT_CHAR_ARRAY == pF->m_eType )
            {
                pF->get_str_from_buf();
            }
        }

        return ret;
    }

    int odbc_recordset::set_str_to_buf()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); iter != field_list.end(); ++iter )
        {
            odbc_field::T * pF = *iter;
            if( i_stmt::VT_CHAR_ARRAY == pF->m_eType )
            {
                pF->set_str_to_buf();
            }
        }

        return ret;
    }

    int odbc_recordset::bind_query_col_by_recordset()
    {
        int ret = 0;

        if( m_bFindQueryCol )
        {
            return ret;
        }

        odbc_field::LIST f_list;
        char name[1024] = {0};
        int nDigitNum = 0;
        int nCanNull = 0;
        int nColNum = 0;
        int nType = 0;
        int nSize = 0;

        m_pStmt->get_col_num( nColNum );
        field_list.swap( f_list );

        for( int i = 0; i < nColNum; ++i )
        {
            ret = m_pStmt->get_col_info( i, name, sizeof( name ), nType, nSize, nDigitNum, nCanNull );
            if( 0 != ret )
            {
                break;
            }
            odbc_field::T * pF = 0;
            xos_stl::init_pool_item( pF );
            pF->set_type( (i_stmt::enumValueType)nType, nSize, nDigitNum );
            pF->set_name( name );
            push( pF );
        }

        if( 0 != ret )
        {
            field_list.swap( f_list );
        }
        else
        {
            bind_query_col();
        }

        f_list.put_back_to_pool();

        return ret;
    }

    int odbc_recordset::push( odbc_field * pF )
    {
        int ret = 0;
        pF->m_nIndex = (int)field_list.size();
        field_list.push_back( (odbc_field::T *)pF );
        return ret;
    }

    // 
    // 清除查询结果
    // 
    int odbc_recordset::clear()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); iter != field_list.end(); ++iter )
        {
            odbc_field::T * pF = *iter;
            pF->clear_value();
        }

        return ret;
    }

    int odbc_recordset::init_data()
    {
        int ret = 0;

        m_bFindQueryCol = false;

        m_table_name = "";
        m_sql = "";

        m_pConnect = 0;
        m_pStmt = 0;

        m_pKey = 0;

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // i_recordset method

    // 
    // 添加整数字段
    // 
    int odbc_recordset::push( const char * lpszName, int32_t & data, bool bIsKey )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_I32;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( int32_t );
            pF->i32_ptr = &data;
            pF->m_bIsKey = bIsKey;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_recordset::push( const char * lpszName, int64_t & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_I64;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( int64_t );
            pF->i64_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_recordset::push( const char * lpszName, int16_t & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_I16;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( int16_t );
            pF->i16_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加字节字段
    // 
    int odbc_recordset::push( const char * lpszName, int8_t & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_I8;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( int8_t );
            pF->i8_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加整数字段
    // 
    int odbc_recordset::push( const char * lpszName, uint32_t & data, bool bIsKey )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_U32;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( uint32_t );
            pF->u32_ptr = &data;
            pF->m_bIsKey = bIsKey;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_recordset::push( const char * lpszName, uint64_t & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_U64;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( uint64_t );
            pF->u64_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_recordset::push( const char * lpszName, uint16_t & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_U16;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( uint16_t );
            pF->u16_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加字节字段
    // 
    int odbc_recordset::push( const char * lpszName, uint8_t & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_U8;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( uint8_t );
            pF->u8_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加bool字段
    // 
    int odbc_recordset::push( const char * lpszName, bool & data )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_BOOL;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( bool );
            pF->bool_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加字串字段
    // 
    int odbc_recordset::push( const char * lpszName, xos_box::i_string * lpData )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->set_string( lpszName, lpData );
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加float字段
    // 
    int odbc_recordset::push( const char * lpszName, float & data, int nDigitNum )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_FLOAT;
            pF->m_nDigitnum = nDigitNum;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( float );
            pF->float_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    // 
    // 添加double字段
    // 
    int odbc_recordset::push( const char * lpszName, double & data, int nDigitNum )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool();
            pF->init();
            pF->m_eType = i_stmt::VT_DOUBLE;
            pF->m_nDigitnum = nDigitNum;
            pF->m_name = lpszName;
            pF->m_nBufSize = sizeof( double );
            pF->double_ptr = &data;
        }

        if( 0 == ret )
        {
            push( pF );
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    const char * odbc_recordset::col_name( int nIndex, xos_box::i_string * lpData )
    {
        const char * pRet = 0;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            if( lpData )
            {
                lpData->set( pF->m_name.c_str(), pF->m_name.length() );
            }
            pRet = pF->m_name.c_str();
        }
        return pRet;
    }

    int odbc_recordset::col_num()
    {
        int ret = (int)field_list.size();
        return ret;
    }

    int odbc_recordset::get( int nIndex, int32_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->i32_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, int64_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->i64_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, int16_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->i16_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, int8_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->i8_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, uint32_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->u32_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, uint64_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->u64_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, uint16_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->u16_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, uint8_t & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->u8_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, bool & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->bool_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, xos_box::i_string * lpData )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            lpData->set( pF->m_pStringA );
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, float & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->float_v;
            ret = 0;
        }
        return ret;
    }

    int odbc_recordset::get( int nIndex, double & data )
    {
        int ret = 1;
        odbc_field::T * pF = get( nIndex );
        if( pF )
        {
            data = pF->double_v;
            ret = 0;
        }
        return ret;
    }

    odbc_field::T * odbc_recordset::get( int nIndex )
    {
        odbc_field::T * pRet = 0;
        for( odbc_field::ITER iter = field_list.begin(); iter != field_list.end(); ++iter )
        {
            odbc_field::T * pF = *iter;
            if( pF->m_nIndex == nIndex )
            {
                pRet = pF;
                break;
            }
        }
        return pRet;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // 设置为更改过
    // 
    int odbc_recordset::set_dirty( const char * lpszName )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field::T * pField = *iter;
            if( pField->m_name == lpszName )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = true;
        }

        return ret;
    }

    // 
    // 设置为更改过
    // 
    int odbc_recordset::set_dirty( int nIndex )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field::T * pField = *iter;
            if( pField->m_nIndex == nIndex )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = true;
        }

        return ret;
    }

    // 
    // 设置为更改过
    // 
    int odbc_recordset::set_all_dirty()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field::T * pF = *iter;
            pF->m_bDirty = true;
        }

        return ret;
    }

    // 
    // 恢复为没改过
    // 
    int odbc_recordset::clear_dirty( const char * lpszName )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field::T * pField = *iter;
            if( pField->m_name == lpszName )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = false;
        }

        return ret;
    }

    // 
    // 恢复为没改过
    // 
    int odbc_recordset::clear_dirty( int nIndex )
    {
        int ret = 0;

        odbc_field::T * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field::T * pField = *iter;
            if( pField->m_nIndex == nIndex )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = false;
        }

        return ret;
    }

    // 
    // 恢复为没改过
    // 
    int odbc_recordset::clear_all_dirty()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field::T * pF = *iter;
            pF->m_bDirty = false;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // 设置表名
    // 
    int odbc_recordset::set_table_name( const char * lpszTableName )
    {
        int ret = 0;
        m_table_name = lpszTableName;
        return ret;
    }

    // 
    // 准备结果集句柄
    // 
    int odbc_recordset::prepare_stmt()
    {
        i_stmt * pStmt = 0;
        int ret = 0;
        if( 0 == ret )
        {
            odbc_connect * pDbc = (odbc_connect *)m_pConnect;
            ret = pDbc->create_stmt( &pStmt );
        }
        if( 0 == ret )
        {
            xos_stl::release_interface( m_pStmt );
            m_pStmt = pStmt;
            pStmt = 0;
        }
        xos_stl::release_interface( pStmt );
        return ret;
    }

    // 
    // 准备结果集句柄
    // 
    int odbc_recordset::close_stmt()
    {
        int ret = 0;
        xos_stl::release_interface( m_pStmt );
        return ret;
    }

    //
    // 编译sql
    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    // 
    int odbc_recordset::compile_sql()
    {
        int ret = 0;
        ret = m_pStmt->compile_sql( m_sql.c_str() );
        return ret;
    }

    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    int odbc_recordset::execute_direct( const char * lpszSql )
    {
        int ret = 0;

        if( ( 0 == ret ) && !m_pStmt )
        {
            ret = -1;
        }

        if( 0 == ret )
        {
            set_str_to_buf();
        }

        if( 0 == ret )
        {
            ret = m_pStmt->execute_direct( lpszSql );
        }

        if( 0 == ret )
        {
            bind_query_col_by_recordset();
        }

        return ret;
    }

    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    int odbc_recordset::execute()
    {
        int ret = 0;

        if( ( 0 == ret ) && !m_pStmt )
        {
            ret = -1;
        }

        if( 0 == ret )
        {
            set_str_to_buf();
        }

        if( 0 == ret )
        {
            ret = m_pStmt->execute();
        }

        if( 0 == ret )
        {
            bind_query_col_by_recordset();
        }

        return ret;
    }

    // 
    //  0 : success
    //  1 : pending
    //  2 : no data
    // -1 : failed
    // 
    int odbc_recordset::fetch()
    {
        int ret = 0;

        if( ( 0 == ret ) && !m_pStmt )
        {
            ret = -1;
        }

        if( 0 == ret )
        {
            clear();
        }

        if( 0 == ret )
        {
            ret = m_pStmt->fetch();
        }

        if( 0 == ret )
        {
            get_str_from_buf();
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // SELECT follow_id, topic_id, user_id FROM follow
    // 
    // lpszSql说明：
    // 
    //  not null : where子句。如：where id = 1
    //      null : 全表查询
    // 
    int odbc_recordset::compose_query( const char * lpszSql )
    {
        int ret = 0;

        std::string & sql = m_sql;
        sql = "SELECT ";

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            while( iter != field_list.end() )
            {
                odbc_field::T * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                }
                sql += pF->m_name;
                if( iter != field_list.end() )
                {
                    sql += ", ";
                }
            }
            sql += " FROM " + m_table_name;
        }

        if( ( 0 == ret ) && lpszSql )
        {
            sql += " ";
            sql += lpszSql;
        }

        if( 0 != ret )
        {
            m_sql = "";
        }

        return ret;
    }

    int odbc_recordset::bind_query_col()
    {
        int ret = 0; 

        if( m_bFindQueryCol )
        {
            return ret;
        }

        odbc_field::ITER iter = field_list.begin();
        while( iter != field_list.end() )
        {
            odbc_field::T * pF = *iter++;
            pF->bind_col( m_pStmt );
        }

        m_bFindQueryCol = true;

        return ret;
    }

    // 
    // UPDATE follow SET topic_id = ?, user_id = ? WHERE follow_id = ?
    // 修改
    // 
    int odbc_recordset::compose_update()
    {
        int ret = 0;

        xos_box::i_string * pStr = mgr::container()->box()->string();
        std::string & sql = m_sql;
        sql = "UPDATE " + m_table_name + " SET ";
        odbc_field * pKey = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            bool bIsFirst = true;
            while( iter != field_list.end() )
            {
                odbc_field::T * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                    pKey = pF;
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                if( bIsFirst )
                {
                    bIsFirst = false;
                }
                else
                {
                    sql += ", ";
                }
                sql += pF->m_name + " = ?";
            }
            if( !pKey )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            mgr::container()->crt()->sprintf( pStr, " WHERE %s = %d", pKey->m_name.c_str(), *pKey->i32_ptr );
            sql += pStr->get( 0, 0 );
        }

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            int nIndex = 0;
            while( iter != field_list.end() )
            {
                odbc_field::T * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    pKey = pF;
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                int nOld = pF->m_nIndex;
                pF->m_nIndex = nIndex++;
                pF->bind_param( m_pStmt );
                pF->m_nIndex = nOld;
            }
        }

        if( 0 != ret )
        {
            m_sql = "";
        }

        xos_stl::release_interface( pStr );

        return ret;
    }

    // 
    // "INSERT INTO follow ( topic_id, user_id, content, modify_time, create_time, read_auth, write_auth, del_auth ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )"
    // 添加
    // 
    // declare @t table (id int); 
    // INSERT INTO tb_test( name, opt_dtm, size ) OUTPUT INSERTED.id INTO @t VALUES( ?, ?, ? );
    // SELECT id FROM @t;
    // 
    int odbc_recordset::compose_add()
    {
        int ret = 0;

        std::string & sql = m_sql;
        sql = "INSERT INTO " + m_table_name + "( ";

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            std::string values = " VALUES ( ";
            bool bIsFirst = true;

            while( iter != field_list.end() )
            {
                odbc_field::T * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                if( bIsFirst )
                {
                    bIsFirst = false;
                }
                else
                {
                    values += ", ";
                    sql += ", ";
                }
                sql += pF->m_name;
                values += "?";
            }

            if( !bIsFirst )
            {
                values += " )";
                sql += " )";
            }

            sql += values;
        }

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            int nIndex = 0;
            while( iter != field_list.end() )
            {
                odbc_field::T * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                int nTemp = pF->m_nIndex;
                pF->m_nIndex = nIndex++;
                pF->bind_param( m_pStmt );
                pF->m_nIndex = nTemp;
            }
        }

        if( 0 != ret )
        {
            m_sql = "";
        }

        return ret;
    }

    // 
    // DELETE FROM follow WHERE follow_id = %d
    // 删除
    // 
    int odbc_recordset::compose_del()
    {
        int ret = 0;

        xos_box::i_string * pStr = mgr::container()->box()->string();
        std::string & sql = m_sql;
        sql = "DELETE FROM " + m_table_name + " WHERE ";
        odbc_field * pKey = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            while( iter != field_list.end() )
            {
                odbc_field::T * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                    pKey = pF;
                    break;
                }
            }
            if( !pKey )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            mgr::container()->crt()->sprintf( pStr, "%s = %d", pKey->m_name.c_str(), *pKey->i32_ptr );
            sql += pStr->get(0,0);
        }

        if( 0 != ret )
        {
            m_sql = "";
        }

        xos_stl::release_interface( pStr );

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // 帮助方法
    // 
    int odbc_recordset::set_id( int32_t id )
    {
        int ret = 0;
        if( m_pKey )
        {
            *m_pKey->i32_ptr = id;
        }
        return ret;
    }

    const char * odbc_recordset::sql()
    {
        return m_sql.c_str();
    }

} // xos_odbc
